import dgram from 'dgram'
import { WebSocketServer } from 'ws'
import { EventEmitter } from 'events'

export default class ForzaHorizon extends EventEmitter {
  private udp = dgram.createSocket('udp4')
  constructor(port: number, version = 5) {
    super()
    this.udp.on('message', data => {
      if (version === 5) {
        this.transport(data)
      }
    })
    this.udp.on('error', console.log)

    this.udp.bind(port, '127.0.0.1', () => console.log(1))
  }

  destroy() {
    this.udp.close()
  }

  private transport(data: Buffer) {
    const dvd = new DataView(data.buffer)
    const dv = new DataView(new ArrayBuffer(84))
    dv.setUint8(0, dvd.getInt32(0, true) & 0xFF) // 1 running   0 menu
    dv.setUint8(1, dvd.getInt32(224, true) & 0xFF) // Corresponds to EDrivetrainType; 0 = FWD, 1 = RWD, 2 = AWD
    dv.setUint8(2, data[307 + 12])    // gear
    dv.setUint8(3, 7)                 // max gear
    dv.setFloat32(4, dvd.getInt8(308 + 12) / 128, true)  // Steer
    dv.setFloat32(8, dvd.getInt8(303 + 12) / 256, true)  // Accel
    dv.setFloat32(12, dvd.getInt8(304 + 12) / 256, true)  // Brake
    dv.setFloat32(16, dvd.getInt8(305 + 12) / 256, true)  // Clutch
    dv.setFloat32(20, dvd.getFloat32(244 + 12, true), true) // speed 
    dv.setFloat32(24, dvd.getFloat32(12, true), true) // EngineIdleRpm
    dv.setFloat32(28, dvd.getFloat32(16, true), true) // CurrentEngineRpm
    dv.setFloat32(32, dvd.getFloat32(8, true), true) // EngineMaxRpm
    dv.setFloat32(36, Math.min(1, Math.max(-1, dvd.getFloat32(20, true) / (2 * 9.8))), true) // g y         max 2 * 9.8
    dv.setFloat32(40, Math.min(1, Math.max(-1, dvd.getFloat32(28, true) / (2 * 9.8))), true) // g x foword  max 2 * 9.8
    dv.setFloat32(44, Math.min(Math.PI, Math.max(-Math.PI, dvd.getFloat32(60, true))), true) // 侧向翻转角度 顺时针为负值  max PI
    dv.setFloat32(48, Math.min(Math.PI, Math.max(-Math.PI, dvd.getFloat32(64, true))), true) // 前后倾斜角度 后仰为负      max PI
    dv.setFloat32(52, dvd.getFloat32(68, true) * 2 - 1, true) // 前左减震变形 -1 ~ 1  正为悬空 即最长
    dv.setFloat32(56, dvd.getFloat32(72, true) * 2 - 1, true) // 前右减震变形 -1 ~ 1  正为悬空 即最长
    dv.setFloat32(60, dvd.getFloat32(76, true) * 2 - 1, true) // 后左减震变形 -1 ~ 1  正为悬空 即最长
    dv.setFloat32(64, dvd.getFloat32(80, true) * 2 - 1, true) // 后右减震变形 -1 ~ 1  正为悬空 即最长
    dv.setFloat32(68, dvd.getFloat32(196, true), true) // 前左减震变形 米 悬空为正
    dv.setFloat32(72, dvd.getFloat32(200, true), true) // 前右减震变形 米 悬空为正
    dv.setFloat32(76, dvd.getFloat32(204, true), true) // 后左减震变形 米 悬空为正
    dv.setFloat32(80, dvd.getFloat32(208, true), true) // 后右减震变形 米 悬空为正
    this.emit('data', dv.buffer)

    // const dataNeed = Buffer.alloc(54, 0)
    // data.copy(dataNeed, 0, 307 + 12, 308 + 12) // u8 Gear
    // dataNeed[1] = 7 // u8 max Gear
    // data.copy(dataNeed, 2, 308 + 12, 309 + 12) // s8 Steer  -127~128
    // data.copy(dataNeed, 3, 303 + 12, 304 + 12) // u8 Accel  0~255
    // data.copy(dataNeed, 4, 304 + 12, 305 + 12) // u8 Brake  0~255
    // data.copy(dataNeed, 5, 305 + 12, 306 + 12) // u8 Clutch  0~255
    // data.copy(dataNeed, 6, 244 + 12, 248 + 12) // f32 Speed m/s
    // data.copy(dataNeed, 10, 12, 16) // f32 EngineIdleRpm
    // data.copy(dataNeed, 14, 16, 20) // f32 CurrentEngineRpm
    // data.copy(dataNeed, 18, 8, 12) // f32 EngineMaxRpm
    // data.copy(dataNeed, 22, 20, 24)  // g y           max 2 * 9.8
    // data.copy(dataNeed, 26, 28, 32)  // g x foword    max 2 * 9.8
    // data.copy(dataNeed, 30, 60, 64)  // 侧向翻转角度 顺时针为负值 dv.getFloat32(60, true) * 180 / Math.PI
    // data.copy(dataNeed, 34, 64, 68)  // 前后倾斜角度 后仰为负 dv.getFloat32(64, true) * 180 / Math.PI
    // // 减震位置 幅值 70 mm
    // data.copy(dataNeed, 38, 196, 200)  // SuspensionTravelMetersFrontLeft     -84.4   220
    // data.copy(dataNeed, 42, 200, 204)  // SuspensionTravelMetersFrontRight    -84.4   220
    // data.copy(dataNeed, 46, 204, 208)  // SuspensionTravelMetersRearLeft      -104.4  220
    // data.copy(dataNeed, 50, 208, 212)  // SuspensionTravelMetersRearRight     -104.4  220
    // // data.copy(dataNeed, 38, 196, 200)  // SuspensionTravelMetersFrontLeft     -84.4   220
    // // data.copy(dataNeed, 42, 200, 204)  // SuspensionTravelMetersFrontRight    -84.4   220
    // // data.copy(dataNeed, 46, 204, 208)  // SuspensionTravelMetersRearLeft      -104.4  220
    // // data.copy(dataNeed, 50, 208, 212)  // SuspensionTravelMetersRearRight     -104.4  220
    // this.emit('data', dataNeed)
    if ((dvd.getInt32(0, true) & 0xFF) === 1) {
      console.log(data.byteLength)
    }
  }
}